const cloud = require("wx-server-sdk");
const dayjs = require("dayjs");

cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV });

const db = cloud.database();
const _ = db.command;

const NEW_ORDER_TEMPLATE = process.env.TEMPLATE_NEW_ORDER || "";
const ORDER_UPDATE_TEMPLATE = process.env.TEMPLATE_ORDER_UPDATE || "";

function ok(data = {}) {
  return { code: 200, data };
}

function fail(message, code = 500) {
  return { code, message };
}

async function safeSendSubscribeMessage({ touser, templateId, data, page }) {
  if (!templateId || !touser) return;
  try {
    await cloud.openapi.subscribeMessage.send({ touser, templateId, data, page });
  } catch (error) {
    console.warn("订阅消息发送失败", error);
  }
}

async function ensureUser(openId) {
  const collection = db.collection("users");
  const { data } = await collection.where({ _openid: openId }).limit(1).get();
  if (data.length) {
    return data[0];
  }
  const defaultProfile = {
    nickname: "我的心动对象",
    avatarUrl: "",
    role: "diner",
    partnerOpenId: "",
    tastePreferences: [],
    createdAt: db.serverDate(),
  };
  const res = await collection.add({ data: defaultProfile });
  const created = await collection.doc(res._id).get();
  return created.data;
}

async function getUserByOpenId(openId) {
  if (!openId) return null;
  const { data } = await db.collection("users").where({ _openid: openId }).limit(1).get();
  return data.length ? data[0] : null;
}

async function bootstrapHandler(_, context) {
  const openId = context.OPENID;
  const user = await ensureUser(openId);
  const partner = user.partnerOpenId ? await getUserByOpenId(user.partnerOpenId) : null;

  let dishes = [];
  if (user.role === "chef") {
    const { data } = await db
      .collection("dishes")
      .where({ chefOpenId: openId })
      .orderBy("createdAt", "desc")
      .limit(100)
      .get();
    dishes = data;
  } else if (partner) {
    const { data } = await db
      .collection("dishes")
      .where({ chefOpenId: partner._openid, isActive: true })
      .orderBy("createdAt", "desc")
      .limit(100)
      .get();
    dishes = data;
  }

  const favoritesRes = await db
    .collection("favorites")
    .where({ userOpenId: openId })
    .get();

  const orderFilter = user.role === "chef" ? { chefOpenId: openId } : { userOpenId: openId };
  const ordersRes = await db
    .collection("orders")
    .where(orderFilter)
    .orderBy("createdAt", "desc")
    .limit(20)
    .get();

  return {
    envId: process.env.TCB_ENV || "",
    userProfile: user,
    partnerProfile: partner,
    dishes,
    favorites: favoritesRes.data,
    orders: ordersRes.data,
  };
}

async function dishesListHandler(params, context) {
  const { role = "diner", category, status, page = 1, pageSize = 20 } = params;
  const openId = context.OPENID;
  let filter = {};

  if (role === "chef") {
    filter.chefOpenId = openId;
    if (status) {
      filter.isActive = status === "active";
    }
  } else {
    const user = await ensureUser(openId);
    if (!user.partnerOpenId) {
      return { dishes: [], total: 0, hasMore: false };
    }
    filter.chefOpenId = user.partnerOpenId;
    filter.isActive = true;
  }

  if (category) {
    filter.category = category;
  }

  const collection = db.collection("dishes");
  const offset = (page - 1) * pageSize;
  const query = collection.where(filter).orderBy("createdAt", "desc");

  const [{ data }, totalInfo] = await Promise.all([
    query.skip(offset).limit(pageSize).get(),
    collection.where(filter).count(),
  ]);

  return {
    dishes: data,
    total: totalInfo.total,
    hasMore: page * pageSize < totalInfo.total,
  };
}

async function dishesCreateHandler(params, context) {
  const openId = context.OPENID;
  const user = await ensureUser(openId);
  if (user.role !== "chef") {
    throw new Error("仅厨师可创建菜品");
  }
  const payload = {
    chefOpenId: openId,
    name: params.name,
    price: params.price,
    images: params.images || [],
    category: params.category || "热菜",
    cookingTime: params.cookingTime || 20,
    isActive: true,
    isFavorite: !!params.isFavorite,
    description: params.description || "",
    dailyLimit: params.dailyLimit ?? 0,
    todayOrdered: 0,
    createdAt: db.serverDate(),
  };
  const res = await db.collection("dishes").add({ data: payload });
  const dish = await db.collection("dishes").doc(res._id).get();
  return { dish: dish.data };
}

async function dishesUpdateHandler(params, context) {
  const { _id, ...rest } = params;
  const openId = context.OPENID;
  const dishDoc = await db.collection("dishes").doc(_id).get();
  if (!dishDoc.data || dishDoc.data.chefOpenId !== openId) {
    throw new Error("无权限编辑此菜品");
  }
  await db.collection("dishes").doc(_id).update({
    data: {
      ...rest,
    },
  });
  const updated = await db.collection("dishes").doc(_id).get();
  return { dish: updated.data };
}

async function dishesToggleHandler(params, context) {
  const { dishId, isActive } = params;
  const openId = context.OPENID;
  const dish = await db.collection("dishes").doc(dishId).get();
  if (!dish.data || dish.data.chefOpenId !== openId) {
    throw new Error("无权限修改状态");
  }
  await db.collection("dishes").doc(dishId).update({ data: { isActive } });
  const updated = await db.collection("dishes").doc(dishId).get();
  return { dish: updated.data };
}

async function dishesFavoriteHandler(params, context) {
  const { dishId, isFavorite } = params;
  const openId = context.OPENID;
  const dish = await db.collection("dishes").doc(dishId).get();
  if (!dish.data || dish.data.chefOpenId !== openId) {
    throw new Error("无权限");
  }
  await db.collection("dishes").doc(dishId).update({ data: { isFavorite } });
  const updated = await db.collection("dishes").doc(dishId).get();
  return { dish: updated.data };
}

async function listOrdersByRole(role, openId, status) {
  const filter = role === "chef" ? { chefOpenId: openId } : { userOpenId: openId };
  if (status) {
    filter.status = status;
  }
  const query = db.collection("orders").where(filter).orderBy("createdAt", "desc");
  const { data } = await query.limit(50).get();
  return data;
}

async function ordersListHandler(params, context) {
  const { role = "diner", status } = params;
  const openId = context.OPENID;
  const orders = await listOrdersByRole(role, openId, status);
  return { orders };
}

async function validateDishAvailability(dishId, quantity) {
  const dishDoc = await db.collection("dishes").doc(dishId).get();
  const dish = dishDoc.data;
  if (!dish) {
    throw new Error("菜品不存在");
  }
  if (!dish.isActive) {
    throw new Error(`${dish.name} 已下架`);
  }
  if (dish.dailyLimit > 0 && dish.todayOrdered + quantity > dish.dailyLimit) {
    throw new Error(`${dish.name} 今日已售罄`);
  }
  return dish;
}

async function ordersSubmitHandler(params, context) {
  const openId = context.OPENID;
  const user = await ensureUser(openId);
  if (!user.partnerOpenId) {
    throw new Error("请先绑定你的厨师伴侣");
  }
  const chef = await getUserByOpenId(user.partnerOpenId);
  if (!chef) {
    throw new Error("厨师信息无效");
  }
  const items = params.items || [];
  if (!items.length) {
    throw new Error("请至少选择一道菜");
  }

  let totalAmount = 0;
  const dishSnapshots = [];
  for (const item of items) {
    const dish = await validateDishAvailability(item.dishId, item.quantity);
    dishSnapshots.push({
      dishId: dish._id,
      dishName: dish.name,
      price: dish.price,
      quantity: item.quantity,
    });
    totalAmount += dish.price * item.quantity;
  }

  const now = new Date();
  const orderData = {
    chefOpenId: chef._openid,
    chefNickname: chef.nickname,
    userOpenId: openId,
    userNickname: user.nickname,
    status: "pending",
    dishes: dishSnapshots,
    totalAmount,
    userNote: params.userNote || "",
    sweetMessage: params.sweetMessage || "",
    isUrgent: !!params.isUrgent,
    createdAt: now.toISOString(),
    acceptedAt: "",
    completedAt: "",
  };

  const res = await db.collection("orders").add({ data: orderData });
  const order = await db.collection("orders").doc(res._id).get();

  await Promise.all(
    items.map((item) =>
      db
        .collection("dishes")
        .doc(item.dishId)
        .update({ data: { todayOrdered: _.inc(item.quantity) } })
    )
  );

  await safeSendSubscribeMessage({
    touser: chef._openid,
    templateId: NEW_ORDER_TEMPLATE,
    page: "pages/chef/orders/index",
    data: {
      thing1: { value: "甜蜜订单" },
      thing2: { value: dishSnapshots.map((d) => d.dishName).join("、").slice(0, 20) || "新订单" },
      time3: { value: dayjs(now).format("HH:mm") },
    },
  });

  return { order: order.data };
}

async function ordersAcceptHandler(params, context) {
  const { orderId } = params;
  const openId = context.OPENID;
  const orderDoc = await db.collection("orders").doc(orderId).get();
  const order = orderDoc.data;
  if (!order || order.chefOpenId !== openId) {
    throw new Error("无权操作此订单");
  }
  if (order.status !== "pending") {
    throw new Error("订单状态已更新");
  }
  const acceptedAt = new Date().toISOString();
  await db.collection("orders").doc(orderId).update({
    data: {
      status: "cooking",
      acceptedAt,
    },
  });

  await db.collection("messages").add({
    data: {
      orderId,
      fromOpenId: openId,
      toOpenId: order.userOpenId,
      content: "大厨已接单，开始准备咯~",
      type: "system_notification",
      createdAt: new Date().toISOString(),
    },
  });

  await safeSendSubscribeMessage({
    touser: order.userOpenId,
    templateId: ORDER_UPDATE_TEMPLATE,
    page: `pages/order/detail/index?id=${orderId}`,
    data: {
      thing1: { value: "大厨开始下厨" },
      thing2: { value: "请稍候片刻，香味正在蔓延" },
      time3: { value: dayjs().format("HH:mm") },
    },
  });

  const updated = await db.collection("orders").doc(orderId).get();
  return { order: updated.data };
}

async function ordersReadySoonHandler(params, context) {
  const { orderId } = params;
  const openId = context.OPENID;
  const orderDoc = await db.collection("orders").doc(orderId).get();
  const order = orderDoc.data;
  if (!order || order.chefOpenId !== openId) {
    throw new Error("无权操作");
  }
  await db.collection("messages").add({
    data: {
      orderId,
      fromOpenId: openId,
      toOpenId: order.userOpenId,
      content: "快好啦，再等我一下下~",
      type: "system_notification",
      createdAt: new Date().toISOString(),
    },
  });

  await safeSendSubscribeMessage({
    touser: order.userOpenId,
    templateId: ORDER_UPDATE_TEMPLATE,
    page: `pages/order/detail/index?id=${orderId}`,
    data: {
      thing1: { value: "爱心餐快好了" },
      thing2: { value: "大厨已经准备收尾" },
      time3: { value: dayjs().format("HH:mm") },
    },
  });

  return {};
}

async function ordersCompleteHandler(params, context) {
  const { orderId } = params;
  const openId = context.OPENID;
  const orderDoc = await db.collection("orders").doc(orderId).get();
  const order = orderDoc.data;
  if (!order || order.chefOpenId !== openId) {
    throw new Error("无权操作");
  }
  const completedAt = new Date().toISOString();
  await db.collection("orders").doc(orderId).update({
    data: {
      status: "ready",
      completedAt,
    },
  });

  await safeSendSubscribeMessage({
    touser: order.userOpenId,
    templateId: ORDER_UPDATE_TEMPLATE,
    page: `pages/order/detail/index?id=${orderId}`,
    data: {
      thing1: { value: "爱心餐完成啦" },
      thing2: { value: "快来领取今日的甜蜜" },
      time3: { value: dayjs().format("HH:mm") },
    },
  });

  const updated = await db.collection("orders").doc(orderId).get();
  return { order: updated.data };
}

async function ordersRejectHandler(params, context) {
  const { orderId, reason = "" } = params;
  const openId = context.OPENID;
  const orderDoc = await db.collection("orders").doc(orderId).get();
  const order = orderDoc.data;
  if (!order || order.chefOpenId !== openId) {
    throw new Error("无权操作");
  }
  await db.collection("orders").doc(orderId).update({
    data: {
      status: "cancelled",
      cancelReason: reason,
    },
  });

  await safeSendSubscribeMessage({
    touser: order.userOpenId,
    templateId: ORDER_UPDATE_TEMPLATE,
    page: `pages/order/detail/index?id=${orderId}`,
    data: {
      thing1: { value: "订单被婉拒" },
      thing2: { value: reason.slice(0, 18) || "大厨暂时无法接单" },
      time3: { value: dayjs().format("HH:mm") },
    },
  });

  const updated = await db.collection("orders").doc(orderId).get();
  return { order: updated.data };
}

async function ordersDetailHandler(params, context) {
  const { orderId } = params;
  const openId = context.OPENID;
  const orderDoc = await db.collection("orders").doc(orderId).get();
  const order = orderDoc.data;
  if (!order || (order.chefOpenId !== openId && order.userOpenId !== openId)) {
    throw new Error("无权查看");
  }
  return { order };
}

async function favoritesAddHandler(params, context) {
  const openId = context.OPENID;
  const dishId = params.dishId;
  if (!dishId) {
    throw new Error("缺少菜品ID");
  }
  const collection = db.collection("favorites");
  const existed = await collection.where({ userOpenId: openId, dishId }).limit(1).get();
  if (existed.data.length) {
    return { favorite: existed.data[0] };
  }
  const res = await collection.add({
    data: {
      userOpenId: openId,
      dishId,
      createdAt: db.serverDate(),
    },
  });
  const favorite = await collection.doc(res._id).get();
  return { favorite: favorite.data };
}

async function favoritesRemoveHandler(params, context) {
  const openId = context.OPENID;
  const dishId = params.dishId;
  await db.collection("favorites").where({ userOpenId: openId, dishId }).remove();
  return {};
}

function generateCode() {
  const source = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
  let code = "";
  for (let i = 0; i < 4; i += 1) {
    code += source.charAt(Math.floor(Math.random() * source.length));
  }
  return code;
}

async function bindGenerateCodeHandler(_, context) {
  const openId = context.OPENID;
  const user = await ensureUser(openId);
  if (user.role !== "chef") {
    throw new Error("仅厨师可以生成绑定码");
  }
  const code = generateCode();
  const expiresAt = dayjs().add(5, "minute").toDate();
  await db.collection("bindCodes").add({
    data: {
      chefOpenId: openId,
      bindCode: code,
      expiresAt,
      createdAt: db.serverDate(),
    },
  });
  return { bindCode: code, expiresAt: expiresAt.toISOString() };
}

async function bindPartnerHandler(params, context) {
  const openId = context.OPENID;
  const user = await ensureUser(openId);
  const bindCode = (params.bindCode || "").toUpperCase();
  if (!bindCode) {
    throw new Error("请输入绑定码");
  }
  const collection = db.collection("bindCodes");
  const { data } = await collection.where({ bindCode }).limit(1).get();
  if (!data.length) {
    throw new Error("绑定码无效");
  }
  const record = data[0];
  if (dayjs().isAfter(record.expiresAt)) {
    throw new Error("绑定码已过期");
  }
  const chef = await getUserByOpenId(record.chefOpenId);
  if (!chef) {
    throw new Error("厨师信息不存在");
  }

  await db.runTransaction(async (transaction) => {
    const users = transaction.collection("users");
    await users.where({ _openid: openId }).update({ data: { partnerOpenId: record.chefOpenId } });
    await users.where({ _openid: record.chefOpenId }).update({ data: { partnerOpenId: openId } });
    await transaction.collection("bindCodes").doc(record._id).remove();
  });

  return {
    chefInfo: {
      nickname: chef.nickname,
      avatarUrl: chef.avatarUrl,
    },
  };
}

async function messagesSendHandler(params, context) {
  const openId = context.OPENID;
  const { orderId, content, type = "text" } = params;
  if (!orderId || !content) {
    throw new Error("消息内容不完整");
  }
  const orderDoc = await db.collection("orders").doc(orderId).get();
  const order = orderDoc.data;
  if (!order || (order.chefOpenId !== openId && order.userOpenId !== openId)) {
    throw new Error("无权发送消息");
  }
  const toOpenId = order.chefOpenId === openId ? order.userOpenId : order.chefOpenId;
  const message = {
    orderId,
    fromOpenId: openId,
    toOpenId,
    content: String(content).slice(0, 200),
    type,
    createdAt: new Date().toISOString(),
  };
  const res = await db.collection("messages").add({ data: message });
  const created = await db.collection("messages").doc(res._id).get();
  return { message: created.data };
}

const ACTIONS = {
  bootstrap: bootstrapHandler,
  dishesList: dishesListHandler,
  dishesCreate: dishesCreateHandler,
  dishesUpdate: dishesUpdateHandler,
  dishesToggle: dishesToggleHandler,
  dishesFavorite: dishesFavoriteHandler,
  ordersList: ordersListHandler,
  ordersSubmit: ordersSubmitHandler,
  ordersAccept: ordersAcceptHandler,
  ordersReadySoon: ordersReadySoonHandler,
  ordersComplete: ordersCompleteHandler,
  ordersReject: ordersRejectHandler,
  ordersDetail: ordersDetailHandler,
  favoritesAdd: favoritesAddHandler,
  favoritesRemove: favoritesRemoveHandler,
  bindGenerateCode: bindGenerateCodeHandler,
  bindPartner: bindPartnerHandler,
  messagesSend: messagesSendHandler,
};

exports.main = async (event, context) => {
  const { action, ...payload } = event;
  if (!action || !ACTIONS[action]) {
    return fail("不支持的操作", 400);
  }
  try {
    const data = await ACTIONS[action](payload, context);
    return ok(data);
  } catch (error) {
    console.error("云函数执行错误", action, error);
    return fail(error.message || "服务异常");
  }
};
